/*** 
 * @_______________#########_______________________ 
 * @______________############_____________________ 
 * @______________#############____________________ 
 * @_____________##__###########___________________ 
 * @____________###__######_#####__________________ 
 * @____________###_#######___####_________________ 
 * @___________###__##########_####________________ 
 * @__________####__###########_####_______________ 
 * @________#####___###########__#####_____________ 
 * @_______######___###_########___#####___________ 
 * @_______#####___###___########___######_________ 
 * @______######___###__###########___######_______ 
 * @_____######___####_##############__######______ 
 * @____#######__#####################_#######_____ 
 * @____#######__##############################____ 
 * @___#######__######_#################_#######___ 
 * @___#######__######_######_#########___######___ 
 * @___#######____##__######___######_____######___ 
 * @___#######________######____#####_____#####____ 
 * @____######________#####_____#####_____####_____ 
 * @_____#####________####______#####_____###______ 
 * @______#####______;###________###______#________ 
 * @________##_______####________####______________ 
 * @
 * @Author: ipk518 121206530@qq.com
 * @Date: 2025-05-30 14:58:00
 * @LastEditors: ipk518 121206530@qq.com
 * @LastEditTime: 2025-10-14 15:30:08
 * @FilePath: /etws-sxk2307/src/gnss/gnss.cpp
 * @Description: 
 * @你把时间投在专业上，两三年，你就能在圈子里小有名气。四五年，你就能靠这个专业赚钱。过了10年以上，你就能成为这个领域的专家
 * @Copyright (c) 2025 by etws@quyujiang, All Rights Reserved. 
 */

#include "gnss.h"
#include "Server.h"

#define GNSS_LOG_OPEN 0


gnss::gnss()
    :m_gnssUart(nullptr)
    ,m_threadRun(false)
    ,m_gnssTh(nullptr)
    

{
    qlog_i("创建GNSS工作流程.");
    memset(&m_update,0,sizeof(m_update));
}



gnss::~gnss()
{
    m_threadRun = false;
    if (m_gnssTh != nullptr) {
        m_gnssTh->join();
        delete m_gnssTh;
        m_gnssTh = nullptr;
    }
}


bool gnss::Init(const char *uartName)
{
    m_gnssUart  = new uartLite(1000);
    if(m_gnssUart != nullptr) {
        m_gnssUart->Init(uartName,115200);
        m_threadRun = true;
    }
    m_gnssTh = new std::thread(std::bind(&gnss::Task,this));
    return true;
}

void gnss::make()
{
    // 时间hhmmss.sss格式
    if (!gnss_data.gnrmc.utc_time.empty()) {
        // 使用 strncpy 避免缓冲区溢出，并手动添加字符串结束符
        (void)strncpy((char *)gnss_data.gnss_data_output.utc_time, gnss_data.gnrmc.utc_time.data(), sizeof(gnss_data.gnss_data_output.utc_time));
    }

    // A=定位，V=未定
    gnss_data.gnss_data_output.location_status = gnss_data.gnrmc.location_status;

    // 纬度ddmm.mmmm，度分格
    if (!gnss_data.gnrmc.latitude.empty()) {
        (void)strncpy((char *)gnss_data.gnss_data_output.latitude, gnss_data.gnrmc.latitude.data(), sizeof(gnss_data.gnss_data_output.latitude));
    }

    // 纬度N(北纬)或S(南纬)
    gnss_data.gnss_data_output.latitude_latitude = gnss_data.gnrmc.latitude_latitude;

    // 经度dddmm.mmmm，度分格
    if (!gnss_data.gnrmc.longitude.empty()) {
        (void)strncpy((char *)gnss_data.gnss_data_output.longitude, gnss_data.gnrmc.longitude.data(), sizeof(gnss_data.gnss_data_output.longitude));
    }

    // 经度E(东经)或W(西经)
    gnss_data.gnss_data_output.longitude_latitude = gnss_data.gnrmc.longitude_latitude;

    // DDMMYY格式
    if (!gnss_data.gnrmc.utc_data.empty()) {
        (void)strncpy((char *)gnss_data.gnss_data_output.utc_data, gnss_data.gnrmc.utc_data.data(), sizeof(gnss_data.gnss_data_output.utc_data));
    }


}

struct GpsUpdateStatus* gnss::Get()
{
    make();
    memcpy((uint8_t *)&m_update,(uint8_t *)&gnss_data.gnss_data_output.utc_time[0],sizeof(m_update));
    return &m_update;
}


void gnss::Task(gnss *args)
{
#define GPS_DATA_ENTITY_TIMEOUT 500
#define GNSS_HEAD '$'   //句子以$开头
//句子以回车和换行符结束
#define GNSS_CR '\r'    // 回车符
#define GNSS_LF '\n'    // 换行符
#define GNSS_END "\r\n"    // 句子以回车和换行符结束
    

	int waitDataTimeCount=0;
	char c = 0;
    std::string sentence;

    
	while(args->m_threadRun)
	{
        if (sysRunStatus == SYS_INIT) {
			qlog_d("GNSS解析线程暂停运行...");
            std::this_thread::sleep_for(std::chrono::milliseconds(600));
            continue;
		}

        if(args->m_gnssUart->dataIsValid()) {
            c = args->m_gnssUart->take();
            if(GNSS_HEAD == c) // 找到起始符
            {
                sentence.clear();
                sentence += c;
                waitDataTimeCount = 0;
                while(true) {
                    if(args->m_gnssUart->dataIsValid()) {
                        c = args->m_gnssUart->take();
                        sentence += c;

                        if(sentence.size() >= 2 && sentence.substr(sentence.size() - 2) == GNSS_END) { // 找到结束符
                            break;
                        }
                    } else {
                        std::this_thread::sleep_for(std::chrono::milliseconds(10));
                        waitDataTimeCount++;
                        if(waitDataTimeCount > GPS_DATA_ENTITY_TIMEOUT) {
                            waitDataTimeCount = 0;
                            qlog_e("gnss receive data timeout");
                            break;
                        }
                    }
                }

                if(!sentence.empty() && sentence.substr(sentence.size() - 2) == GNSS_END) {
                    args->parse(sentence,&args->gnss_data);
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
            }
        } else {
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
        
    }
}





gnssModbusRtu::gnssModbusRtu()
{

}

gnssModbusRtu::~gnssModbusRtu()
{
    gnssIsInit.store(false, std::memory_order_relaxed);  
    qlog_e("释放gnssModbusRtu::gnssIsInit.");
    g_Sess.Close();
}

gnssModbusRtu& gnssModbusRtu::Instance()
{
	static gnssModbusRtu _agent;
	return _agent;
}


static void OnRecvFrom(int sockid, char *data, int len, int ip, int port, void* param)
{
    (void)sockid;(void)param;
    gnssModbusRtu::Instance().Recv((unsigned char *)data,len);
#if (GNSS_LOG_OPEN == 1)
    qlog_n("收到GNSS响应端口:%d",port);
    // gnssModbusRtu::Instance().m_gnssPort = port;
    // gnssModbusRtu::Instance().m_gnssIp = ip;
#endif
}

bool gnssModbusRtu::Init(const char *ip, int port)
{
    m_gnssIp = inet_addr(dastIp);
    m_gnssPort = port;
    qlog_n("gnss UdpServer ip:%s port:%d",ip,port);
    char *prctl = (char*)"gnssUdp";
	if (g_Sess.Open(ip,port, OnRecvFrom, (void *)prctl) < 0)
	{
		qlog_e("gnss UdpServer open error");
		return -1;
	}
    qlog_i("gnss UdpServer initialized ...");
    gnssIsInit.store(true, std::memory_order_relaxed);  // 使用原子操作设置值
	// g_Sess.m_pTimeOutCB = OnTimeOut;
    return true;
}

/*** 
 * @description:    读取寄存器
 * @param {uint16_t} reg
 * @param {uint16_t} num
 * @return {*}
 */
void gnssModbusRtu::read(uint16_t reg, uint16_t num)
{
    if(!gnssIsInit.load(std::memory_order_relaxed))  // 使用原子操作读取值
    {
        qlog_n("gnss 没有初始化");
        return;
    }
    // std::lock_guard<std::mutex> lock(sendMutex);
    startReg[0] = reg & 0xFF; // 寄存器地址低字节
    startReg[1] = reg >> 8; // 寄存器地址高字节
    regNum[0] = num & 0xFF; // 寄存器数量低字节
    regNum[1] = num >> 8; // 寄存器数量高字节

    //打包
    readCmd[0] = modbusId;
    readCmd[1] = rFunctionCode;
    readCmd[2] = startReg[1];
    readCmd[3] = startReg[0];
    readCmd[4] = regNum[1];
    readCmd[5] = regNum[0];

    uint16_t iCrc = CRC16_MODBUS(readCmd,6);
    crc[0] = iCrc & 0xFF;   // 校验低字节
    crc[1] = iCrc >> 8;     // 校验高字节
    readCmd[6] = crc[0];
    readCmd[7] = crc[1];
    Send(readCmd,8);
}

/*** 
 * @description: 写入寄存器
 * @param {uint16_t} reg
 * @param {uint16_t} num
 * @param {uint8_t} *data
 * @return {*}
 */
void gnssModbusRtu::write(uint16_t reg, uint16_t num, uint16_t *data)
{
    if(!gnssIsInit.load(std::memory_order_relaxed))  // 使用原子操作读取值
    {
        qlog_e("gnss 没有初始化");
        return;
    }
    startReg[0] = reg & 0xFF;
    startReg[1] = reg >> 8;
    regNum[0] = num & 0xFF;
    regNum[1] = num >> 8;

    writeCmd[0] = modbusId;
    writeCmd[1] = wFunctionCode;
    writeCmd[2] = startReg[1];
    writeCmd[3] = startReg[0];
    writeCmd[4] = regNum[1];
    writeCmd[5] = regNum[0];
    writeCmd[6] = num * 2; // 数据字节数

    memcpy(writeCmd+7,(uint8_t *)data,num * 2);

    uint16_t icrc = CRC16_MODBUS(writeCmd,7+num*2);
    crc[0] = icrc & 0xFF;   // 校验低字节
    crc[1] = icrc >> 8;     // 校验高字节
    writeCmd[7+num*2] = crc[0];
    writeCmd[8+num*2] = crc[1];
    Send(writeCmd,8+num*2);
}



int gnssModbusRtu::Send(uint8_t *data, int len)
{
    size_t sendLen = len;
    static uint8_t udpHrBuff[256];
    if ((len > 0) && (data == nullptr)) {
        return -1;
    }
    if (len < 0) {
        return -2;
    }
    if ( len > sizeof(udpHrBuff) ) {
        qlog_e("gnss udp databuf too short:%d",len);
        return -3;
    }
    memcpy(udpHrBuff,data,sendLen);

#if (GNSS_LOG_OPEN == 1)
    qlog_hexdump("gnss modbus sendto:",16,udpHrBuff,sendLen);
#endif
    return g_Sess.Send((char *)udpHrBuff, sendLen, m_gnssIp, m_gnssPort);
}

//每次都读取所有寄存器
//TO：66 03 02 52 00 02 6C 75
//RESPONSE: 66 03 04 88 A0 96 00 A8 D7    (0x96A088)
void gnssModbusRtu::Recv(unsigned char *data, int len)
{
    if(!gnssIsInit.load(std::memory_order_relaxed))  // 使用原子操作读取值
    {
        qlog_e("gnss 没有初始化");
        return;
    }
    if (len < 5) {
        qlog_e("gnss udp databuf too short:%d",len);
        return;
    }
    if (data[0] != modbusId) {
        qlog_e("gnss modbus id error:%d",data[0]);
        return;
    }
    
    uint16_t iCrc = CRC16_MODBUS(data,len-2);
    uint16_t gpsCrc = (uint16_t)( data[len-1] << 8 | data[len-2] );
#if (GNSS_LOG_OPEN == 1)
    qlog_n("calculate crc:%#x,gps %#x.",iCrc,gpsCrc);
    qlog_hexdump("gnss modbus response:",16,data,len);
#endif
    if( iCrc == gpsCrc )
    {	
        memcpy((uint8_t *)&response,data,len);

        if (Server::Instance().getSharePtr() != nullptr) { //接收到应答
                uint16_t id = 0x0700; //GNSS
                Server::Instance().getSharePtr()->addResponse(m_devMap[id], "successfully");
        }
    }

}

void gnssModbusRtu::getData(gnssUpdateRtu *data)
{
    if(!gnssIsInit.load(std::memory_order_relaxed))  // 使用原子操作读取值
    {
        qlog_e("gnss 没有初始化");
        return;
    }

    memcpy((uint8_t *)&m_gnssAll,(uint8_t *)&response.data,sizeof(gnssRTUData));
    
    memcpy((uint8_t *)&m_update,&m_gnssAll.fen,sizeof(uint16_t)*12);
    memcpy((uint8_t *)&m_update.utc_time,(uint8_t *)&m_gnssAll.utc_time,sizeof(gnssUpdateRtu) - 12);

    memcpy((uint8_t *)data,(uint8_t *)&m_update,sizeof(gnssUpdateRtu));
#if (GNSS_LOG_OPEN == 1)
    qlog_hexdump("m_gnssAll:",16,(uint8_t *)&m_gnssAll,sizeof(gnssRTUData));
    qlog_hexdump("m_update:",16,(uint8_t *)&m_update,sizeof(gnssUpdateRtu));
#endif
}

/*** 
 * @description: 获取指定寄存器数据
 * @param {uint16_t} reg 寄存器地址
 * @param {uint16_t} *data 数据指针
 * @param {uint16_t} num 数据数量(最多85个)
 * @return {*}
 */
void gnssModbusRtu::getSpecificReg(uint16_t reg, uint16_t *data, uint16_t num)
{
    if(!gnssIsInit.load(std::memory_order_relaxed))  // 使用原子操作读取值
    {
        qlog_e("gnss 没有初始化");
        return;
    }
    if (num > 85) {
        qlog_e("gnss最大可读寄存器数量85个:%d",num);
        return;
    }
    qlog_n("获取寄存器:%d,数量:%d",reg,num);
    memcpy(data,&response.data[reg-527],num*2);
}
